////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_FIBERS_H__
#define __WN_FIBERS_H__

#include "WNCore/inc/WNPlatform.h"
#include "WNCore/inc/WNTypes.h"
#include "WNCore/inc/WNTime.h"
#include "WNMemory/inc/WNAllocation.h"

#define WN_FIBER_FUNCTION(_function, _input) WN_VOID* WN_CDECL_BEGIN _function(WN_VOID* _input) WN_CDECL_END

typedef WN_VOID* (WN_CDECL_BEGIN *WN_FIBER_FUNCTION_T)(WN_VOID* _input) WN_CDECL_END;

namespace WNFibers {
    struct WNFiberPrivateData;

    struct WNFiberData {
        WN_SIZE_T           runnable;            // are we allowed to be run currently
        WN_UINT32           sleeptype;           // how are we sleeping
        WN_POINTER          startVal;            // value to pass in
        WN_POINTER          retVal;              // return value

        union {
            WN_UINT32       sleepval;            // what is that value we are sleeping on
            WN_UINT32       sleepTicks;
        };

        WNFiberPrivateData* privateData;
    };

    WN_VOID WNFiberYield();
    WN_VOID WNFiberSleep(WN_UINT32 _time);
    WN_VOID WNFiberSleepWithAlarm(WN_UINT32 _alarmticks);
    WN_VOID WNFiberReturn(WN_POINTER _returnval);

    class WNFiberManager {
    public:
        virtual WN_BOOL      Initialize(WN_UINT32 _maxStacks, WN_BOOL _updateOnDemand, WN_TIME_FUNCTION_T _timeFunction = WN_NULL) = 0;
        virtual WNFiberData* CreateFiber(WN_FIBER_FUNCTION_T _function, WN_POINTER _startValue, WN_UINT32 _stackSize, WN_POINTER _userData = WN_NULL) = 0;
        virtual WN_BOOL      QueuedThreads() = 0;
        virtual WN_BOOL      UpdateQueues(WN_UINT32 _time) = 0;
        virtual WNFiberData* GetNextStack() = 0;
        virtual WN_VOID      RunNextStack(WN_BOOL _continuous) = 0;
        virtual WN_UINT32    GetTime() = 0;
    };

    WNFiberManager* WNGetFiberManager();
    WNFiberManager* WNGetFiberManager(WN_MALLOC_FUNCTION_T _allocator);
}

#endif // __WN_FIBERS_H__
